import http from 'node:http';
import type net from 'node:net';
import express from 'express';
import bodyParser from 'body-parser';
import { promisify } from 'node:util';

export type HttpServerOptions = {
	bodyParser?: express.NextFunction | false;
    port?: number;
};

export type ExtendedHttpTestServer = {
	http: http.Server;         // 原始 HTTP 服务器实例
	url: string;               // 服务器URL
	port: number;              // 服务器端口
	hostname: string;          // 服务器主机名
	close: () => Promise<any>; // 关闭服务器的方法
} & express.Express;

export const createHttpTestServer = async (options: HttpServerOptions = {}): Promise<ExtendedHttpTestServer> => {
	/**
     服务器创建和配置

     - 创建 Express 应用实例并扩展其类型
     - 用 Express 应用创建 HTTP 服务器
     - 禁用 ETag (避免缓存问题)
     */
    const server = express() as ExtendedHttpTestServer;
	server.http = http.createServer(server);

	server.set('etag', false);

    /**
     中间件配置
     */
	if (options.bodyParser !== false) {
        // 配置 JSON 解析器
		server.use(
			bodyParser.json({
				limit: '1mb',
				type: 'application/json',
				...options.bodyParser,
			}),
		);
        // 配置文本解析器
		server.use(
			bodyParser.text({
				limit: '1mb',
				type: 'text/plain',
				...options.bodyParser,
			}),
		);
        // 配置 URL 编码解析器
		server.use(
			bodyParser.urlencoded({
				limit: '1mb',
				type: 'application/x-www-form-urlencoded',
				extended: true,
				...options.bodyParser,
			}),
		);
        // 配置原始数据解析器
		server.use(
			bodyParser.raw({
				limit: '1mb',
				type: 'application/octet-stream',
				...options.bodyParser,
			}),
		);
	}

	const listen = promisify(server.http.listen.bind(server.http));
    const close = promisify(server.http.close.bind(server.http));

    // 启动服务器
    await listen(options.port || 0);

	server.port = (server.http.address() as net.AddressInfo).port;
	server.url = `http://localhost:${server.port}`;
	server.hostname = 'localhost';

	server.close = async (): Promise<void> => {
        await close();
    };

	return server;
};